package com.wave.wavesystem.develop.codeGenetrate.service.impl;

import wave.common.pojo.entity.KV;
import com.wave.wavesystem.config.TemplateMart;
import com.wave.wavesystem.develop.codeGenetrate.pojo.dto.CodeGenerateDTO;
import com.wave.wavesystem.develop.codeGenetrate.pojo.entity.*;
import com.wave.wavesystem.develop.codeGenetrate.pojo.wrapper.PathWrapper;
import com.wave.wavesystem.develop.codeGenetrate.pojo.wrapper.TableFieldWrapper;
import com.wave.wavesystem.develop.codeGenetrate.service.CodeGenerateService;
import com.wave.wavesystem.develop.codeGenetrate.mapper.DatabaseMapper;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 夕下风波
 * @date 2024-12-19 22:10
 * @description
 */
@Slf4j
@Service
public class CodeGenerateServiceImpl implements CodeGenerateService {

    @Resource
    private TemplateMart templateMart;

    @Resource
    private DatabaseMapper databaseMapper;

    private static CodeGenerateDTO generateParam;

    @Override
    public boolean codeGenerate(CodeGenerateDTO codeGenerateDTO) {
        generateParam = codeGenerateDTO;
        generateFileFolder();
        generateEntity();
        generateDTO();
        generateVO();
        generateMapper();
        generateMapperXml();
        generateService();
        generateServiceImpl();
        generateController();
//        generateWrapper();
        generateApi();
        generateView();
        generateViewDetail();
        generateViewRemove();
        generateViewSave();
        generateViewSearch();
        generateViewTable();
        generateViewUpdate();
        generateViewActionBar();
        return true;
    }

    private void generateFileFolder() {
        String backendPath = generateParam.getGenerateBackendPath();
        String entityHumpName = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), false);
        generateParam.setEntityHumpName(entityHumpName);
        List<String> backendFile = createBackendFile(backendPath, entityHumpName);
        String frontPath = generateParam.getGenerateFrontPath();
        String ignoreEntityHumpName = entityHumpName;
        String upperCase = String.valueOf(ignoreEntityHumpName.charAt(0)).toUpperCase();
        ignoreEntityHumpName = entityHumpName.replaceFirst(String.valueOf(entityHumpName.charAt(0)), upperCase);
        List<String> frontendFile = createFrontendFile(frontPath, ignoreEntityHumpName);
        List<String> pathList = new ArrayList<>();
        pathList.addAll(frontendFile);
        pathList.addAll(backendFile);
        try {
            for (String filePath : pathList) {
                String[] split = filePath.split("/");
                StringBuilder dirs = new StringBuilder();
                for (int i = 0; i < split.length; i++) {
                    dirs.append(split[i]);
                    if (i == split.length - 1) {
                        new File(dirs.toString()).createNewFile();
                        continue;
                    }
                    if (!new File(dirs.toString()).exists()) {
                        new File(dirs.toString()).mkdirs();
                    }
                    dirs.append("/");
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private List<String> createBackendFile(String backendPath, String entityHumpName) {
        String replacedBackendPath = backendPath.replace("\\", "/");
        String entityPath = PathWrapper.getEntityPath(replacedBackendPath, entityHumpName);
        String dtoPath = PathWrapper.getDTOPath(replacedBackendPath, entityHumpName);
        String voPath = PathWrapper.getVOPath(replacedBackendPath, entityHumpName);
        String mapperPath = PathWrapper.getMapperPath(replacedBackendPath, entityHumpName);
        String mapperXmlPath = PathWrapper.getMapperXmlPath(replacedBackendPath, entityHumpName);
        String servicePath = PathWrapper.getServicePath(replacedBackendPath, entityHumpName);
        String serviceImplPath = PathWrapper.getServiceImplPath(replacedBackendPath, entityHumpName);
        String wrapperPath = PathWrapper.getWrapperPath(replacedBackendPath, entityHumpName);
        String controllerPath = PathWrapper.getControllerPath(replacedBackendPath, entityHumpName);
        return List.of(entityPath, dtoPath, voPath, mapperPath, mapperXmlPath, servicePath, serviceImplPath, wrapperPath, controllerPath);
    }

    private List<String> createFrontendFile(String frontendPath, String ignoreHumpName) {
        String replacedFrontendPath = frontendPath.replace("\\", "/");
        String viewPath = PathWrapper.getViewPath(replacedFrontendPath, ignoreHumpName);
        String detailPath = PathWrapper.getViewDetailPath(replacedFrontendPath, ignoreHumpName);
        String removePath = PathWrapper.getViewRemovePath(replacedFrontendPath, ignoreHumpName);
        String savePath = PathWrapper.getViewSavePath(replacedFrontendPath, ignoreHumpName);
        String searchPath = PathWrapper.getViewSearchPath(replacedFrontendPath, ignoreHumpName);
        String tablePath = PathWrapper.getViewTablePath(replacedFrontendPath, ignoreHumpName);
        String updatePath = PathWrapper.getViewUpdatePath(replacedFrontendPath, ignoreHumpName);
        String actionBarPath = PathWrapper.getViewActionBarPath(replacedFrontendPath, ignoreHumpName);
        String apiPath = PathWrapper.getApiPath(replacedFrontendPath, ignoreHumpName);
        return List.of(viewPath, detailPath, removePath, savePath, searchPath, tablePath, updatePath, actionBarPath, apiPath);
    }


    private void writeToFile(Object model, String filePath, Template template) {
        File targetFile = new File(filePath);
        // 写入模板到目标文件
        try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), StandardCharsets.UTF_8))) {
            template.process(model, out);
            System.out.println("模板生成成功，文件路径：" + targetFile.getAbsolutePath());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private void generateEntity() {
        List<KV<String, String>> tables = databaseMapper.getTablesByDatabaseName(generateParam.getDbName());
        String tableComment = tables.stream().filter(item -> item.getV().equals(generateParam.getTableName())).toList().get(0).getK();
        generateParam.setTableComment(tableComment);
        Template entityTemplate = templateMart.getEntity();
        EntityGN entityGN = new EntityGN();
        entityGN.setTableName(generateParam.getTableName());
        entityGN.setAuthorName(generateParam.getAuthor());
        entityGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        entityGN.setTableComment(tableComment);
        entityGN.setPackageName(generateParam.getPackageName());
        entityGN.setHumpName(generateParam.getEntityHumpName());
        List<TableField> tableFields = genTableField();
        entityGN.setTableFields(tableFields);
        String filePath = PathWrapper.getEntityPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(entityGN, filePath, entityTemplate);
    }


    private void generateDTO() {
        Template dtoTemplate = templateMart.getDTO();
        DTOGN dtoGN = new DTOGN();
        dtoGN.setAuthorName(generateParam.getAuthor());
        dtoGN.setPackageName(generateParam.getPackageName());
        dtoGN.setHumpName(generateParam.getEntityHumpName());
        dtoGN.setTableComment(generateParam.getTableComment());
        List<TableField> tableFields = genTableField();
        dtoGN.setTableFields(tableFields);
        dtoGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getDTOPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(dtoGN, filePath, dtoTemplate);
    }

    private void generateVO() {
        Template voTemplate = templateMart.getVO();
        VOGN voGN = new VOGN();
        voGN.setAuthorName(generateParam.getAuthor());
        voGN.setPackageName(generateParam.getPackageName());
        voGN.setHumpName(generateParam.getEntityHumpName());
        voGN.setTableComment(generateParam.getTableComment());
        voGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getVOPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(voGN, filePath, voTemplate);
    }

    private void generateMapper() {
        Template mapperTemplate = templateMart.getMapper();
        MapperGN mapperGN = new MapperGN();
        mapperGN.setAuthorName(generateParam.getAuthor());
        mapperGN.setPackageName(generateParam.getPackageName());
        mapperGN.setHumpName(generateParam.getEntityHumpName());
        mapperGN.setTableComment(generateParam.getTableComment());
        mapperGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getMapperPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(mapperGN, filePath, mapperTemplate);
    }

    private void generateMapperXml() {
        Template mapperXmlTemplate = templateMart.getMapperXml();
        MapperXmlGN xmlGN = new MapperXmlGN();
        xmlGN.setPackageName(generateParam.getPackageName());
        xmlGN.setHumpName(generateParam.getEntityHumpName());
        String filePath = PathWrapper.getMapperXmlPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(xmlGN, filePath, mapperXmlTemplate);
    }

    private void generateService() {
        Template serviceTemplate = templateMart.getService();
        ServiceGN serviceGN = new ServiceGN();
        serviceGN.setAuthorName(generateParam.getAuthor());
        serviceGN.setPackageName(generateParam.getPackageName());
        serviceGN.setHumpName(generateParam.getEntityHumpName());
        serviceGN.setTableComment(generateParam.getTableComment());
        serviceGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getServicePath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(serviceGN, filePath, serviceTemplate);
    }

    private void generateServiceImpl() {
        Template serviceImplTemplate = templateMart.getServiceImpl();
        ServiceImplGN serviceImplGN = new ServiceImplGN();
        serviceImplGN.setAuthorName(generateParam.getAuthor());
        serviceImplGN.setPackageName(generateParam.getPackageName());
        serviceImplGN.setHumpName(generateParam.getEntityHumpName());
        serviceImplGN.setTableComment(generateParam.getTableComment());
        serviceImplGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getServiceImplPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(serviceImplGN, filePath, serviceImplTemplate);
    }

    private void generateController() {
        Template controllerTemplate = templateMart.getController();
        ControllerGN controllerGN = new ControllerGN();
        controllerGN.setAuthorName(generateParam.getAuthor());
        controllerGN.setPackageName(generateParam.getPackageName());
        controllerGN.setHumpName(generateParam.getEntityHumpName());
        controllerGN.setTableComment(generateParam.getTableComment());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        controllerGN.setIgnoreFirstHumpName(ignoreFirst);
        controllerGN.setGenerateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String filePath = PathWrapper.getControllerPath(generateParam.getGenerateBackendPath(), generateParam.getEntityHumpName());
        writeToFile(controllerGN, filePath, controllerTemplate);
    }

    private void generateApi() {
        Template api = templateMart.getApi();
        ApiGN apiGN = new ApiGN();
        apiGN.setAuthorName(generateParam.getAuthor());
        apiGN.setPackageName(generateParam.getPackageName());
        apiGN.setHumpName(generateParam.getEntityHumpName());
        apiGN.setTableComment(generateParam.getTableComment());
        apiGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        apiGN.setIgnoreFirstHumpName(ignoreFirst);
        String filePath = PathWrapper.getApiPath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(apiGN, filePath, api);
    }

    private void generateView() {
        Template view = templateMart.getView();
        ViewGN viewGN = new ViewGN();
        viewGN.setAuthorName(generateParam.getAuthor());
        viewGN.setPackageName(generateParam.getPackageName());
        viewGN.setHumpName(generateParam.getEntityHumpName());
        viewGN.setTableComment(generateParam.getTableComment());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewGN.setIgnoreFirstHumpName(ignoreFirst);
        String filePath = PathWrapper.getViewPath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewGN, filePath, view);
    }

    private void generateViewDetail() {
        Template viewDetail = templateMart.getViewDetail();
        ViewDetailGN viewDetailGN = new ViewDetailGN();
        viewDetailGN.setAuthorName(generateParam.getAuthor());
        viewDetailGN.setPackageName(generateParam.getPackageName());
        viewDetailGN.setHumpName(generateParam.getEntityHumpName());
        viewDetailGN.setTableComment(generateParam.getTableComment());
        viewDetailGN.setTableComment(generateParam.getTableComment());
        viewDetailGN.setServiceName(generateParam.getServiceName());
        List<TableField> tableFields = genTableField();
        viewDetailGN.setTableFields(tableFields);
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewDetailGN.setIgnoreFirstHumpName(ignoreFirst);
        String filePath = PathWrapper.getViewDetailPath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewDetailGN, filePath, viewDetail);
    }

    private void generateViewRemove() {
        Template viewRemove = templateMart.getViewRemove();
        ViewRemoveGN viewRemoveGN = new ViewRemoveGN();
        viewRemoveGN.setAuthorName(generateParam.getAuthor());
        viewRemoveGN.setPackageName(generateParam.getPackageName());
        viewRemoveGN.setHumpName(generateParam.getEntityHumpName());
        viewRemoveGN.setTableComment(generateParam.getTableComment());
        viewRemoveGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewRemoveGN.setIgnoreFirstHumpName(ignoreFirst);
        String filePath = PathWrapper.getViewRemovePath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewRemoveGN, filePath, viewRemove);
    }

    private void generateViewSave() {
        Template viewSave = templateMart.getViewSave();
        ViewSaveGN viewSaveGN = new ViewSaveGN();
        viewSaveGN.setAuthorName(generateParam.getAuthor());
        viewSaveGN.setPackageName(generateParam.getPackageName());
        viewSaveGN.setHumpName(generateParam.getEntityHumpName());
        viewSaveGN.setTableComment(generateParam.getTableComment());
        viewSaveGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewSaveGN.setIgnoreFirstHumpName(ignoreFirst);
        List<TableField> tableFields = genTableField();
        viewSaveGN.setTableFields(tableFields);
        String filePath = PathWrapper.getViewSavePath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewSaveGN, filePath, viewSave);
    }

    private void generateViewSearch() {
        Template viewSearch = templateMart.getViewSearch();
        ViewSearchGN viewSearchGN = new ViewSearchGN();
        viewSearchGN.setAuthorName(generateParam.getAuthor());
        viewSearchGN.setPackageName(generateParam.getPackageName());
        viewSearchGN.setHumpName(generateParam.getEntityHumpName());
        viewSearchGN.setTableComment(generateParam.getTableComment());
        viewSearchGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewSearchGN.setIgnoreFirstHumpName(ignoreFirst);
        List<TableField> tableFields = genTableField();
        viewSearchGN.setTableFields(tableFields);
        String filePath = PathWrapper.getViewSearchPath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewSearchGN, filePath, viewSearch);
    }

    private void generateViewTable() {
        Template viewTable = templateMart.getViewTable();
        ViewTableGN viewTableGN = new ViewTableGN();
        viewTableGN.setAuthorName(generateParam.getAuthor());
        viewTableGN.setPackageName(generateParam.getPackageName());
        viewTableGN.setHumpName(generateParam.getEntityHumpName());
        viewTableGN.setTableComment(generateParam.getTableComment());
        viewTableGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewTableGN.setIgnoreFirstHumpName(ignoreFirst);
        List<TableField> tableFields = genTableField();
        viewTableGN.setTableFields(tableFields);
        String filePath = PathWrapper.getViewTablePath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewTableGN, filePath, viewTable);
    }

    private void generateViewUpdate() {
        Template viewUpdate = templateMart.getViewUpdate();
        ViewUpdateGN viewUpdateGN = new ViewUpdateGN();
        viewUpdateGN.setAuthorName(generateParam.getAuthor());
        viewUpdateGN.setPackageName(generateParam.getPackageName());
        viewUpdateGN.setHumpName(generateParam.getEntityHumpName());
        viewUpdateGN.setTableComment(generateParam.getTableComment());
        viewUpdateGN.setServiceName(generateParam.getServiceName());
        String ignoreFirst = TableFieldWrapper.fieldNameToHumpType(generateParam.getPrefix(), generateParam.getTableName(), true);
        viewUpdateGN.setIgnoreFirstHumpName(ignoreFirst);
        List<TableField> tableFields = genTableField();
        viewUpdateGN.setTableFields(tableFields);
        String filePath = PathWrapper.getViewUpdatePath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewUpdateGN, filePath, viewUpdate);
    }

    private void generateViewActionBar() {
        Template actionBar = templateMart.getViewActionBar();
        ViewActionBarGN viewActionBarGN = new ViewActionBarGN();
        viewActionBarGN.setAuthorName(generateParam.getAuthor());
        viewActionBarGN.setPackageName(generateParam.getPackageName());
        viewActionBarGN.setHumpName(generateParam.getEntityHumpName());
        viewActionBarGN.setTableComment(generateParam.getTableComment());
        viewActionBarGN.setServiceName(generateParam.getServiceName());
        String filePath = PathWrapper.getViewActionBarPath(generateParam.getGenerateFrontPath(), generateParam.getEntityHumpName());
        writeToFile(viewActionBarGN, filePath, actionBar);
    }

    private List<TableField> genTableField() {
        List<KV<String, String>> fields = databaseMapper.getFieldsByTableName(generateParam.getDbName(), generateParam.getTableName());
        List<TableField> tableFields = new ArrayList<>();
        for (KV<String, String> item : fields) {
            String propertyName = TableFieldWrapper.fieldNameToHumpType("", item.getK(), true);
            if (propertyName.equals("id") || propertyName.equals("createUser") || propertyName.equals("createTime")
                    || propertyName.equals("updateUser") || propertyName.equals("updateTime") || propertyName.equals("isDelete"))
                continue;
            TableField tableField = new TableField();
            tableField.setComment((String) item.getExpand());
            tableField.setType(TableFieldWrapper.fieldPropertyType(item.getV()));
            tableField.setName(propertyName);
            tableFields.add(tableField);
        }
        return tableFields;
    }

    private void generateWrapper() {
        Template entity = templateMart.getWrapper();
    }

}
